package com.sardine.base.esm.binding;

import com.sardine.base.esm.session.EsmSession;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 上海京东到家元信信息技术有限公司<br>
 * Created with IntelliJ IDEA.
 * Date:2017/7/11
 * Time:14:48
 * esm 接口的 注解映射代理类
 * @author daifeng<br>
 *         daifeng@imdada.cn
 * @since JDK 1.7 <br>
 * Copyright (c) 2017 imdada System Incorporated All Rights Reserved.
 */
public class EsmAnnotationMapperProxy<T> implements InvocationHandler,Serializable {
    private static final Logger logger = LoggerFactory.getLogger(EsmAnnotationMapperProxy.class);

    /**
     * es 的操作 session
     */
    private final EsmSession esmSession;
    /**
     * 映射的接口
     */
    private final Class<T> annotationInterface;

    /**
     * 接口映射的方法
     */
    private final Map<Method,EsmMapperMethod> methodCache;

    public EsmAnnotationMapperProxy(EsmSession esmSession, Class<T> annotationInterface, Map<Method, EsmMapperMethod> methodCache) {
        this.esmSession = esmSession;
        this.annotationInterface = annotationInterface;
        this.methodCache = methodCache;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable t) {
                throw ExceptionUtil.unwrapThrowable(t);
            }
        }
        final EsmMapperMethod mapperMethod = cachedMapperMethod(method);
        return mapperMethod.execute(esmSession, args);
    }


    private EsmMapperMethod cachedMapperMethod(Method method) {
        EsmMapperMethod mapperMethod = methodCache.get(method);
        if (mapperMethod == null) {
            mapperMethod = new EsmMapperMethod(annotationInterface, method, esmSession.getConfiguration());
            methodCache.put(method, mapperMethod);
        }
        return mapperMethod;
    }
}
